home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / CPP / WFC010.ZIP / SRC / SERIAL.CPP < prev    next >
C/C++ Source or Header  |  1995-12-07  |  15KB  |  587 lines

  1. #include <wfc.h>
  2. #pragma hdrstop
  3.  
  4. /*
  5. ** Author: Samuel R. Blackburn
  6. ** CI$: 76300,326
  7. ** Internet: sammy@sed.csc.com
  8. **
  9. ** You can use it any way you like as long as you don't try to sell it.
  10. **
  11. ** Any attempt to sell WFC in source code form must have the permission
  12. ** of the original author. You can produce commercial executables with
  13. ** WFC but you can't sell WFC.
  14. **
  15. ** Copyright, 1995, Samuel R. Blackburn
  16. **
  17. ** $Workfile: $
  18. ** $Revision: $
  19. ** $Modtime: $
  20. */
  21.  
  22. #if defined( _DEBUG )
  23. #undef THIS_FILE
  24. static char BASED_CODE THIS_FILE[] = __FILE__;
  25. #endif
  26.  
  27. IMPLEMENT_SERIAL( CSerialFile, CDummyFile, 1 )
  28.  
  29. #if defined( _DEBUG )
  30. #define new DEBUG_NEW
  31. #endif
  32.  
  33. const WORD CSerialFile::flowXonXoff  = 1;
  34. const WORD CSerialFile::flowRtsCts   = 2;
  35. const WORD CSerialFile::flowSoftware = 1;
  36. const WORD CSerialFile::flowHardware = 2;
  37.  
  38. CSerialFile::CSerialFile()
  39. {
  40.    FileHandle = INVALID_HANDLE_VALUE;
  41.    ::ZeroMemory( &m_CommunicationsStatus, sizeof( m_CommunicationsStatus ) );
  42.    m_IsOpen = FALSE;
  43.    Name.Empty();
  44. }
  45.  
  46. CSerialFile::~CSerialFile()
  47. {
  48.    Close();
  49. }
  50.  
  51. void CSerialFile::Close( void )
  52. {
  53.    TRACE1( "CSerialFile::Close( \"%s\" )\n", (LPCTSTR) Name );
  54.  
  55.    if ( FileHandle == INVALID_HANDLE_VALUE )
  56.    {
  57.       m_IsOpen = FALSE;
  58.       return;
  59.    }
  60.  
  61.    m_ClearError( __LINE__ );
  62.  
  63.    ::EscapeCommFunction( FileHandle, CLRDTR );
  64.  
  65.    ::PurgeComm( FileHandle, PURGE_TXABORT |
  66.                             PURGE_RXABORT |
  67.                             PURGE_TXCLEAR |
  68.                             PURGE_RXCLEAR );
  69.  
  70.    if ( m_hFile != (UINT) CFile::hFileNull )
  71.    {
  72.       CDummyFile::Close();
  73.    }
  74.  
  75.    FileHandle = INVALID_HANDLE_VALUE;
  76.    m_IsOpen   = FALSE;
  77. }
  78.  
  79. #if defined( _DEBUG )
  80.  
  81. void CSerialFile::Dump( CDumpContext& dump_context ) const
  82. {
  83.    CDummyFile::Dump( dump_context );
  84.  
  85.    dump_context << "m_IsOpen = " << m_IsOpen << "\n";
  86.    dump_context << "m_CommunicationErrorCodes = " << m_CommunicationErrorCodes << "\n";
  87.    dump_context << "m_CommunicationsStatus is a COMSTAT:\n";
  88.    dump_context << "{\n";
  89.    dump_context << "   fCtsHold = "  << m_CommunicationsStatus.fCtsHold  << "\n";
  90.    dump_context << "   fDsrHold = "  << m_CommunicationsStatus.fDsrHold  << "\n";
  91.    dump_context << "   fRlsdHold = " << m_CommunicationsStatus.fRlsdHold << "\n";
  92.    dump_context << "   fXoffHold = " << m_CommunicationsStatus.fXoffHold << "\n";
  93.    dump_context << "   fXoffSent = " << m_CommunicationsStatus.fXoffSent << "\n";
  94.    dump_context << "   fEof = "      << m_CommunicationsStatus.fEof      << "\n";
  95.    dump_context << "   fTxim = "     << m_CommunicationsStatus.fTxim     << "\n";
  96.    dump_context << "   fReserved = " << m_CommunicationsStatus.fReserved << "\n";
  97.    dump_context << "   cbInQue = "   << m_CommunicationsStatus.cbInQue   << "\n";
  98.    dump_context << "   cbOutQue = "  << m_CommunicationsStatus.cbOutQue  << "\n";
  99.    dump_context << "}\n";
  100. }
  101.  
  102. #endif // _DEBUG
  103.  
  104. DWORD CSerialFile::GetFlowControl( void )
  105. {
  106.    ASSERT( FileHandle != INVALID_HANDLE_VALUE );
  107.  
  108.    if ( FileHandle == INVALID_HANDLE_VALUE )
  109.    {
  110.       return( 0 );
  111.    }
  112.  
  113.    DWORD flow_control = 0;
  114.  
  115.    CDeviceControlBlock device_control_block;
  116.  
  117.    if ( ::GetCommState( FileHandle, &device_control_block ) == FALSE )
  118.    {
  119.       m_ErrorCode = ::GetLastError();
  120.       ASSERT( FALSE );
  121.       return( 0 );
  122.    }
  123.  
  124.    if ( device_control_block.fOutxDsrFlow == TRUE &&
  125.         device_control_block.fOutxCtsFlow == TRUE )
  126.    {
  127.  
  128.       flow_control = flowHardware;
  129.    }
  130.  
  131.    if ( device_control_block.fInX  == TRUE &&
  132.         device_control_block.fOutX == TRUE )
  133.    {
  134.       flow_control |= flowSoftware;
  135.    }
  136.  
  137.    return( flow_control );
  138. }
  139.  
  140. void CSerialFile::m_ClearError( int line_number )
  141. {
  142.    ASSERT( FileHandle != INVALID_HANDLE_VALUE );
  143.  
  144.    if ( FileHandle == INVALID_HANDLE_VALUE )
  145.    {
  146.       return;
  147.    }
  148.  
  149.    if ( ::ClearCommError( FileHandle, &m_CommunicationErrorCodes, &m_CommunicationsStatus ) == FALSE )
  150.    {
  151.       m_ErrorCode = ::GetLastError();
  152.  
  153.       if ( m_ErrorCode == ERROR_INVALID_HANDLE )
  154.       {
  155.          FileHandle = INVALID_HANDLE_VALUE;
  156.       }
  157.  
  158.       return;
  159.    }
  160.  
  161.    if ( m_CommunicationErrorCodes != 0 )
  162.    {
  163.       TCHAR error_message[ 2048 ];
  164.  
  165.       ::ZeroMemory( error_message, sizeof( error_message ) );
  166.  
  167.       if ( m_CommunicationErrorCodes & CE_BREAK )
  168.       {
  169.          ::strcat( error_message, "\r\nThe hardware detected a break condition. (CE_BREAK);" );
  170.       }
  171.  
  172.       if ( m_CommunicationErrorCodes & CE_FRAME )
  173.       {
  174.          ::strcat( error_message, "\r\nThe hardware detected a framing error. (CE_FRAME);" );
  175.          ::PurgeComm( FileHandle, PURGE_RXCLEAR );
  176.       }
  177.  
  178.       if ( m_CommunicationErrorCodes & CE_IOE )
  179.       {
  180.          ::strcat( error_message, "\r\nAn I/O error occurred during communications with the device. (CE_IOE);" );
  181.       }
  182.  
  183.       if ( m_CommunicationErrorCodes & CE_MODE )
  184.       {
  185.          ::strcat( error_message, "\r\nThe requested mode is not supported or the hCommDev parameter is invalid. (CE_MODE);" );
  186.       }
  187.  
  188.       if ( m_CommunicationErrorCodes & CE_OVERRUN )
  189.       {
  190.          ::strcat( error_message, "\r\nA character-buffer overrun has occurred. The next character is lost. (CE_OVERRUN);" );
  191.       }
  192.  
  193.       if ( m_CommunicationErrorCodes & CE_RXOVER )
  194.       {
  195.          m_ErrorCode = CE_RXOVER;
  196.          ::strcat( error_message, "\r\nAn input buffer overflow has occurred. There is either no room in the input buffer, or a character was received after the end-of-file (EOF) character. (CE_RXOVER);" );
  197.       }
  198.  
  199.       if ( m_CommunicationErrorCodes & CE_RXPARITY )
  200.       {
  201.          ::strcat( error_message, "\r\n.The hardware detected a parity error. (CE_RXPARITY);" );
  202.       }
  203.  
  204.       if ( m_CommunicationErrorCodes & CE_TXFULL )
  205.       {
  206.          ::strcat( error_message, "\r\nThe application tried to transmit a character, but the output buffer was full. (CE_TXFULL);" );
  207.       }
  208.  
  209.       if ( m_CommunicationErrorCodes & CE_DNS )
  210.       {
  211.          ::strcat( error_message, "\r\nThe parallel device is not selected. (CE_DNS);" );
  212.       }
  213.  
  214.       if ( m_CommunicationErrorCodes & CE_PTO )
  215.       {
  216.          ::strcat( error_message, "\r\nA time-out occurred on the parallel device. (CE_PTO);" );
  217.       }
  218.  
  219.       if ( m_CommunicationErrorCodes & CE_OOP )
  220.       {
  221.          ::strcat( error_message, "\r\nThe parallel device signaled that it is out of paper. (CE_OOP);" );
  222.       }
  223.  
  224.       TCHAR temp_string[ 100 ];
  225.  
  226.       ::sprintf( temp_string, "%d (%d in input_queue)", line_number, m_CommunicationsStatus.cbInQue );
  227.  
  228.       TRACE1( "%s", error_message );
  229.       TRACE1( "%s\n", temp_string );
  230.    }
  231. }
  232.  
  233. BOOL CSerialFile::IsDataWaiting( void )
  234. {
  235.    ASSERT( FileHandle != INVALID_HANDLE_VALUE );
  236.  
  237.    if ( FileHandle == INVALID_HANDLE_VALUE )
  238.    {
  239.       return( FALSE );
  240.    }
  241.  
  242.    m_ClearError( __LINE__ );
  243.  
  244.    if ( m_CommunicationsStatus.cbInQue > 0 )
  245.    {
  246.       return( TRUE );
  247.    }
  248.    else
  249.    {
  250.       return( FALSE );
  251.    }
  252. }
  253.  
  254. DWORD CSerialFile::NumberOfBytesWaitingToBeRead( void )
  255. {
  256.    ASSERT( FileHandle != INVALID_HANDLE_VALUE );
  257.  
  258.    if ( FileHandle == INVALID_HANDLE_VALUE )
  259.    {
  260.       return( 0 );
  261.    }
  262.  
  263.    m_ClearError( __LINE__ );
  264.  
  265.    return( m_CommunicationsStatus.cbInQue );
  266. }
  267.  
  268. DWORD CSerialFile::NumberOfBytesWaitingToBeWritten( void )
  269. {
  270.    ASSERT( FileHandle != INVALID_HANDLE_VALUE );
  271.  
  272.    if ( FileHandle == INVALID_HANDLE_VALUE )
  273.    {
  274.       return( 0 );
  275.    }
  276.  
  277.    m_ClearError( __LINE__ );
  278.  
  279.    return( m_CommunicationsStatus.cbOutQue );
  280. }
  281.  
  282. #pragma warning( disable : 4100 )
  283.  
  284. BOOL CSerialFile::Open( LPCTSTR channel_name, UINT open_flags, CFileException *exception_p )
  285. {
  286.    ASSERT( channel_name != NULL );
  287.  
  288.    if ( channel_name == NULL )
  289.    {
  290.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  291.       return( FALSE );
  292.    }
  293.  
  294.    if ( m_IsOpen == TRUE )
  295.    {
  296.       Close();
  297.    }
  298.  
  299.    Name = channel_name;
  300.  
  301.    return( Open() );
  302. }
  303.  
  304. #pragma warning( default : 4100 )
  305.  
  306. BOOL CSerialFile::Open( void )
  307. {
  308.    if ( m_IsOpen == TRUE )
  309.    {
  310.       Close();
  311.    }
  312.  
  313.    CString com_port_name( "" );
  314.  
  315.    int index = 0;
  316.    int string_length = Name.GetLength();
  317.  
  318.    while( index < string_length && Name[ index ] != ':' )
  319.    {
  320.       com_port_name += Name[ index ];
  321.       index++;
  322.    }
  323.  
  324.    com_port_name += ':';
  325.  
  326.    CString settings_string( "" );
  327.  
  328.    settings_string = Name.Right( ( string_length - index ) - 1 );
  329.  
  330.    FileHandle = ::CreateFile( (LPCTSTR) com_port_name,
  331.                               GENERIC_READ | GENERIC_WRITE,
  332.                               0,
  333.                               NULL,
  334.                               OPEN_EXISTING,
  335.                               FILE_ATTRIBUTE_NORMAL,
  336.                               NULL );
  337.  
  338.    if ( FileHandle == INVALID_HANDLE_VALUE )
  339.    {
  340.       m_ErrorCode = ::GetLastError();
  341.  
  342.       TRACE1( "CSerialFile::Open(), %d\n", __LINE__ );
  343.       return( FALSE );
  344.    }
  345.  
  346.    if ( ::PurgeComm( FileHandle, PURGE_TXABORT |
  347.                                  PURGE_RXABORT |
  348.                                  PURGE_TXCLEAR |
  349.                                  PURGE_RXCLEAR ) != TRUE )
  350.    {
  351.    }
  352.  
  353.    m_hFile = (HFILE) FileHandle;
  354.  
  355.    CString baud_string( "" );
  356.  
  357.    index = 0;
  358.    string_length = settings_string.GetLength();
  359.  
  360.    while( index < string_length && settings_string[ index ] != ',' )
  361.    {
  362.       baud_string += settings_string[ index ];
  363.       index++;
  364.    }
  365.  
  366.    index++; // Skip over the comma
  367.  
  368.    CString parity_string( "" );
  369.  
  370.    while( index < string_length && settings_string[ index ] != ',' )
  371.    {
  372.       parity_string += settings_string[ index ];
  373.       index++;
  374.    }
  375.  
  376.    index++; // skip the comma
  377.  
  378.    CString data_bits_string( "" );
  379.  
  380.    while( index < string_length && settings_string[ index ] != ',' )
  381.    {
  382.       data_bits_string += settings_string[ index ];
  383.       index++;
  384.    }
  385.  
  386.    index++; // another dang comma
  387.  
  388.    CString stop_bits_string( "" );
  389.  
  390.    while( index < string_length )
  391.    {
  392.       stop_bits_string += settings_string[ index ];
  393.       index++;
  394.    }
  395.  
  396.    CString dcb_string( "" );
  397.  
  398.    dcb_string  = com_port_name;
  399.    dcb_string += " baud=";
  400.    dcb_string += baud_string;
  401.    dcb_string += " parity=";
  402.    dcb_string += parity_string;
  403.    dcb_string += " data=";
  404.    dcb_string += data_bits_string;
  405.    dcb_string += " stop=";
  406.    dcb_string += stop_bits_string;
  407.  
  408.    CDeviceControlBlock device_control_block;
  409.  
  410.    if ( ::GetCommState( FileHandle, &device_control_block ) == FALSE )
  411.    {
  412.       m_ErrorCode = ::GetLastError();
  413.       TRACE1( "CSerialFile::Open() %d\n", __LINE__ );
  414.       Close();
  415.       return( FALSE );
  416.    }
  417.  
  418.    if ( ::BuildCommDCB( dcb_string, &device_control_block ) == FALSE )
  419.    {
  420.       m_ErrorCode = ::GetLastError();
  421.       TRACE1( "CSerialFile::Open() %d\n", __LINE__ );
  422.       Close();
  423.       return( FALSE );
  424.    }
  425.  
  426.    device_control_block.fAbortOnError = FALSE; // Terminate Reads & Writes if there's an error
  427.    device_control_block.fErrorChar    = TRUE;  // Replace any garbled bytes with ErrorChar
  428.    device_control_block.ErrorChar     = ' ';   // Garbage bytes are spaces
  429.    device_control_block.fBinary       = TRUE;  // Ignore EOF
  430.  
  431.    if ( ::SetCommState( FileHandle, &device_control_block ) == FALSE )
  432.    {
  433.       m_ErrorCode = ::GetLastError();
  434.       TRACE1( "CSerialFile::Open() %d\n", __LINE__ );
  435.       Close();
  436.       return( FALSE );
  437.    }
  438.  
  439.    if ( ::SetupComm( FileHandle, 4096, 1024 ) != TRUE )
  440.    {
  441.    }
  442.  
  443.    // assert DTR
  444.  
  445.    if ( ::EscapeCommFunction( FileHandle, SETDTR ) != TRUE )
  446.    {
  447.    }
  448.  
  449.    m_IsOpen = TRUE;
  450.  
  451.    return( TRUE );
  452. }
  453.  
  454. UINT CSerialFile::Read( void *buffer, UINT length )
  455. {
  456.    ASSERT( FileHandle != INVALID_HANDLE_VALUE );
  457.    ASSERT( buffer != NULL );
  458.  
  459.    if ( buffer == NULL || FileHandle == INVALID_HANDLE_VALUE )
  460.    {
  461.       return( 0 );
  462.    }
  463.  
  464.    m_ClearError( __LINE__ );
  465.  
  466.    return( CDummyFile::Read( buffer, length ) );
  467. }
  468.  
  469. void CSerialFile::Serialize( CArchive& archive )
  470. {
  471.    CDummyFile::Serialize( archive );
  472.  
  473.    if ( archive.IsStoring() )
  474.    {
  475.       archive << (DWORD) m_IsOpen;
  476.       archive << Name;
  477.    }
  478.    else
  479.    {
  480.       DWORD temp_dword = 0;
  481.  
  482.       archive >> temp_dword;
  483.       archive >> Name;
  484.  
  485.       m_IsOpen = temp_dword;
  486.  
  487.       if ( m_IsOpen == TRUE )
  488.       {
  489.          Open();
  490.       }
  491.    }
  492. }
  493.  
  494. void CSerialFile::SetFlowControl( DWORD flow_control )
  495. {
  496.    if ( flow_control == 0 )
  497.    {
  498.       return;
  499.    }
  500.  
  501.    ASSERT( FileHandle != INVALID_HANDLE_VALUE );
  502.  
  503.    if ( FileHandle == INVALID_HANDLE_VALUE )
  504.    {
  505.       return;
  506.    }
  507.  
  508.    CDeviceControlBlock device_control_block;
  509.  
  510.    if ( ::GetCommState( FileHandle, &device_control_block ) == FALSE )
  511.    {
  512.       m_ErrorCode = ::GetLastError();
  513.       ASSERT( FALSE );
  514.       return;
  515.    }
  516.  
  517.    if ( flow_control & flowHardware )
  518.    {
  519.       device_control_block.fOutxDsrFlow = TRUE;
  520.       device_control_block.fOutxCtsFlow = TRUE;
  521.    }
  522.    else
  523.    {
  524.       device_control_block.fOutxDsrFlow = FALSE;
  525.       device_control_block.fOutxCtsFlow = FALSE;
  526.    }
  527.  
  528.    if ( flow_control & flowSoftware )
  529.    {
  530.       device_control_block.fInX     = TRUE;
  531.       device_control_block.fOutX    = TRUE;
  532.       device_control_block.XonChar  = 0x11;
  533.       device_control_block.XoffChar = 0x13;
  534.       device_control_block.XonLim   = 100;
  535.       device_control_block.XoffLim  = 100;
  536.    }
  537.    else
  538.    {
  539.       device_control_block.fInX     = FALSE;
  540.       device_control_block.fOutX    = FALSE;
  541.       device_control_block.XonChar  = 0;
  542.       device_control_block.XoffChar = 0;
  543.       device_control_block.XonLim   = 0;
  544.       device_control_block.XoffLim  = 0;
  545.    }
  546.  
  547.    if ( ::SetCommState( FileHandle, &device_control_block ) != TRUE )
  548.    {
  549.       m_ErrorCode = ::GetLastError();
  550.       ASSERT( FALSE );
  551.       return;
  552.    }
  553. }
  554.  
  555. void CSerialFile::Write( const void *buffer, UINT length )
  556. {
  557.    ASSERT( FileHandle != INVALID_HANDLE_VALUE );
  558.    ASSERT( buffer != NULL );
  559.  
  560.    if ( buffer == NULL || FileHandle == INVALID_HANDLE_VALUE )
  561.    {
  562.       return;
  563.    }
  564.  
  565.    m_ClearError( __LINE__ );
  566.  
  567.    CFile::Write( buffer, length );
  568. }
  569.  
  570. void CSerialFile::Write( CString& string_to_write )
  571. {
  572.    ASSERT( FileHandle != INVALID_HANDLE_VALUE );
  573.  
  574.    if ( FileHandle == INVALID_HANDLE_VALUE )
  575.    {
  576.       return;
  577.    }
  578.  
  579.    LPTSTR buffer_p = string_to_write.GetBuffer( 1 );
  580.  
  581.    UINT number_of_bytes = string_to_write.GetLength();
  582.  
  583.    Write( buffer_p, number_of_bytes );
  584.  
  585.    string_to_write.ReleaseBuffer();
  586. }
  587.